package cn.midas.basic.service.impl;

import cn.midas.basic.constant.BaseConstants;
import cn.midas.basic.dto.RejisterDto;
import cn.midas.basic.exception.BusinessException;
import cn.midas.basic.service.IGraphCodeService;

import cn.midas.basic.utils.StrUtils;
import cn.midas.basic.utils.VerifyCodeUtils;
import cn.midas.user.domain.User;
import cn.midas.user.mapper.UserMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class GraphCodeServiceImpl implements IGraphCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;



    /*/**
    * @Title: graph
    * @Description: 发送图片验证码 q
    * @Author: Mr.She
    * @Version: 1.0
    * @Date:  2022/7/6 15:32
    * @Parameters: [imageCodeKey]
    * @Return java.lang.String
    */
    @Override
    public String graph(String imageCodeKey) {
        // 判断key值是否为空 为空抛出自定义异常
            if(StringUtils.isEmpty(imageCodeKey)){
                throw new RuntimeException("参数值为空,请检查");
            }
        // 调用字符串工具类 获取四位随机字符
        String code = StrUtils.getComplexRandomString(4);
        // 把key 和随机四位字符 设置到redis中
        redisTemplate.opsForValue().set(imageCodeKey,code,5, TimeUnit.MINUTES);
        // 将code 值变成图形并编码base64
        String base64Str = VerifyCodeUtils.VerifyCode(100, 35, code);
        // 返回图形base64码
        return base64Str;
    }

    /*/**
    * @Title: smsCode
    * @Description: 发送手机验证码
    * @Author: Mr.She
    * @Version: 1.0
    * @Date:  2022/7/6 15:31
    * @Parameters: [rejisterDto]
    * @Return void
    */
    /*@Override
    public void smsCode(RejisterDto rejisterDto) {
        String imageCodeKey = rejisterDto.getImageCodeKey();
        String phone = rejisterDto.getPhone();
        String imageCodeValue = rejisterDto.getImageCodeValue();
        //1.判断参数为空校验
        if(StringUtils.isEmpty(imageCodeKey) || StringUtils.isEmpty(phone) ||StringUtils.isEmpty(imageCodeValue)){
            throw new BusinessException("参数为空，请填写");
        }
        //2.判断手机号是否存在用户是否已经被注册
        User user = userMapper.loadByPhone(phone);
        if (user != null){
            throw new BusinessException("用户已经存在，请直接登录！");
        }
        //3.判断图形验证码是否存在、是否正确
        Object imageCodeTmp = redisTemplate.opsForValue().get(imageCodeKey);
        if (imageCodeTmp == null){
            throw new BusinessException("图形验证码不存在！");
        }//equalsIgnoreCase
        if (!imageCodeTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("图形验证码错误，请重新填写！");
        }
        //4.前面都通过 用户需要获取新的手机验证码 不能直接发验证码要做业务处理
        //4.1使用业务键拼接手机号从redis中获取到手机验证码register：phone
       String smsCodeKye = BaseConstants.GraphCodeConstants.BUSINESS_REGISTER_PREFIX + phone;
        Object smsCodeValueTmp = redisTemplate.opsForValue().get(smsCodeKye);
        //4.2判断验证码是否为空，为空说明已经过期，生成新的验证码
        String smsCode ="";//存放重新发送验证码
        if (smsCodeValueTmp == null){
            smsCode = StrUtils.getComplexRandomString(4);
        }else {
            String[] smsCodeValueArray = smsCodeValueTmp.toString().split(":");
            Long oldTime = Long.valueOf(smsCodeValueArray[1]);
            long newTime = System.currentTimeMillis();
            // 判断前后时间戳是否大于一分钟
            if (newTime-oldTime<1*60*1000){
                throw new BusinessException("请一分钟后重试！");
            }
            smsCode = smsCodeValueArray[0];
        }
        //5.设置手机验证码到redis中
        String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(smsCodeKye,smsCodeValue,3,TimeUnit.MINUTES);
        //6.发送手机短信验证码
       // SmsUtils.sendMsg(phone,"您的验证码是："+smsCode);
        System.out.println("您的验证码是："+smsCode);
    }*/

    /**
     * @Title: sendSmsCode
     * @Description: 发送短信验证码
     * @Author: Mr.She
     * @Version: 1.0
     * @Date:  2022/6/21 17:30
     * @Parameters: * @param smsCodeKey
     * @Return void
     */
    public void sendSmsCode(String smsCodeKey){
        // 1.从Redis中获取手机验证码 register:phone
        Object smsCodeValueTmp = redisTemplate.opsForValue().get(smsCodeKey);
        // 2.判断验证码是否为空，为空，说明验证码已过期，那么生成新的验证码
        String smsCode = ""; // 用于存放重新发送给用户的验证码
        if(smsCodeValueTmp == null){
            // 1.Redis中手机验证码为空，说明已过期，那么生成新的验证码
            smsCode = StrUtils.getComplexRandomString(4);
        }else {
            // 1.Redis中存在手机验证码，我们需要判断是否超过一分钟，防止恶意请求
            // code:时间戳：这是我们手机验证码在Redis中的格式，我们通过:截取获取到时间戳，判断距离当前时间是否超过一分钟
            String[] smsCodeValueArray = smsCodeValueTmp.toString().split(":");
            // 2.获取到老的时间戳
            Long oldTimeTmp = Long.valueOf(smsCodeValueArray[1]);
            // 3.获取到现在的时间戳
            Long nowTimeTmp = System.currentTimeMillis();
            // 4.判断现在的时间戳减去手机验证码的时间戳，是否大于一分钟的毫秒数，如果小于，说明没有超过一分钟，那么提示用户
            if(nowTimeTmp - oldTimeTmp <= 1*60*1000){
                throw new BusinessException("请一分钟后重试！");
            }
            // 5.如果Redis中还存验证码，并且超过了一分钟，那么使用之前的验证码重置验证码时间即可
            smsCode = smsCodeValueArray[0];
        }

        // 3.设置手机验证码到Redis中，不管是否是第一次获取手机验证码都直接设置到Redis中并设置过期时间为三分钟
        String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        System.out.println(smsCodeValue);
        redisTemplate.opsForValue().set(smsCodeKey, smsCodeValue, 3, TimeUnit.MINUTES);
        System.err.println("     send      "+smsCodeKey);
        // 4.发送短信验证码
        // SmsUtils.sendMsg(phone, "亲：您的验证码是：" + smsCode);
        System.out.println("亲：您的验证码是：" + smsCode);
    }

    /**
     * @Title: isImgCode
     * @Description: 校验图形验证码
     * @Author: Mr.She
     * @Version: 1.0
     * @Date:  2022/6/21 17:37
     * @Parameters: * @param vo
     * @Return void
     */
    public void isImageCode(RejisterDto vo){
        // 1.判断手机号和图形验证码是否为空
        String imageCodeKey = vo.getImageCodeKey();
        String imageCodeValue = vo.getImageCodeValue();
        String phone = vo.getPhone();

        if(StringUtils.isEmpty(imageCodeKey)
                || StringUtils.isEmpty(imageCodeValue)){
            throw new BusinessException("参数错误，请输入正确参数!");
        }

        // 2判断手机号是否被注册，如果被注册提示用户
        // 2.1.根据电话查询用户
        User user = userMapper.loadByPhone(phone);
        // 2.2.如果用户信息不为空，说明此电话已注册用户，那么提示用户登录即可
        if(user != null){
            throw new BusinessException("账号已注册，请直接登录!");
        }

        // 3.校验图形验证码在Redis中是否存在以及是否正确
        // 3.1.根据图形验证码Key值从Redis中获取图形验证码code
        Object imageCodeTmp = redisTemplate.opsForValue().get(imageCodeKey);
        // 3.2.判断Redis中是否存有该Key的图形验证码，如果没有，说明用户非正常手段访问，那么抛出异常
        if(imageCodeTmp == null){
            throw new BusinessException("验证码为空，请输入验证码!");
        }
        // 3.3.获取到了图形验证码，需要判断前端传递的验证码与Redis中存入的是否一致，如果不一致提示用户
        if(!imageCodeTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请输入正确验证码!");
        }
    }

    /**
     * @Title: smsCode
     * @Description: 发送手机验证码
     * @Author: Mr.She
     * @Version: 1.0
     * @Date:  2022/6/6 10:59
     * @Parameters: * @param vo
     * @Return void
     */
    @Override
    public void smsCode(RejisterDto vo) {
        // 1.公共的参数为空判断在此方法中做
        String phone = vo.getPhone();
        String type = vo.getType();

        if(StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(type)){
            throw new BusinessException("参数错误，请输入正确参数!");
        }

        // 2.判断是要做注册账号还是绑定账号
        if("register".equals(type)){
            // 如果type等于register，说明是注册账号发送短信验证码，那么先把注册账号私有业务逻辑做了
            // 1.判断图形验证码
            isImageCode(vo);
            // 2.使用业务键拼接手机号从Redis中获取手机验证码 register:phone
            String smsCodeKey = BaseConstants.GraphCodeConstants.BUSINESS_BINDER_KEY + phone;
            // 3.如果是注册直接发送短信验证码即可
            sendSmsCode(smsCodeKey);
        }else if("binder".equals(type)){
            // 如果type等于binder那么就直接发送短信验证码
            // 1.使用业务键拼接手机号从Redis中获取手机验证码 binder:phone
            String smsCodeKey = BaseConstants.GraphCodeConstants.BUSINESS_BINDER_PREFIX + phone;
            System.err.println("           "+smsCodeKey);
            // 2.如果是注册直接发送短信验证码即可
            sendSmsCode(smsCodeKey);
        }
    }

}
